package com.lifeonwalden.sshpush;

import com.alibaba.fastjson.JSON;
import com.beust.jcommander.JCommander;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
import com.lifeonwalden.sshpush.bean.*;
import com.lifeonwalden.sshpush.constant.ActionType;
import com.lifeonwalden.sshpush.parse.ConfigurationParse;
import com.lifeonwalden.sshpush.process.*;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

public class Main {
    public static void main(String[] args) {

        YesOrNot yesOrNot;
        yesOrNot = new YesOrNot();
        System.out.println("Do you want to input global password : ");
        JCommander.newBuilder().addObject(yesOrNot).build().parse("-confirm");
        ParamPassword globalPwd = new ParamPassword();
        if ("Y".equalsIgnoreCase(yesOrNot.getYesOrNot())) {
            JCommander.newBuilder().addObject(globalPwd).build().parse("-p");
        }

        do {
            ParamConfig config = new ParamConfig();
            JCommander.newBuilder().addObject(config).build().parse("-f");
            run(args[0].concat(config.getConfig()).concat(".json"), globalPwd);

            yesOrNot = new YesOrNot();
            System.out.println("Do you want to run another task set : ");
            JCommander.newBuilder().addObject(yesOrNot).build().parse("-confirm");
        } while ("Y".equalsIgnoreCase(yesOrNot.getYesOrNot()));
    }

    private static void run(String config, ParamPassword globalPwd) {
        Map<String, Session> sessionMap = new HashMap<>();
        try {
            Optional<PushInfo> pushInfoOption = ConfigurationParse.parse(new File(config));
            if (pushInfoOption.isPresent()) {
                PushInfo pushInfo = pushInfoOption.get();
                AuthProcessor.process(pushInfo, globalPwd);

                if (null != pushInfo.getHost() && !pushInfo.getHost().isEmpty()) {
                    JSch jSch = new JSch();
                    for (HostInfo hostInfo : pushInfo.getHost()) {
                        Session session = null;
                        if (hostInfo.getPort() > 0) {
                            session = jSch.getSession(hostInfo.getUser(), hostInfo.getHost(), hostInfo.getPort());
                        } else {
                            session = jSch.getSession(hostInfo.getUser(), hostInfo.getHost());
                        }
                        session.setConfig("StrictHostKeyChecking", "no");
                        session.setPassword(hostInfo.getPassword());
                        session.connect();
                        sessionMap.put(hostInfo.getId(), session);
                    }
                }

                Map<String, TaskInfo> taskInfoMapping = new HashMap<>();
                if (null != pushInfo.getTask()) {
                    for (TaskInfo taskInfo : pushInfo.getTask()) {
                        taskInfoMapping.put(taskInfo.getId(), taskInfo);
                    }
                }

                YesOrNot yesOrNot;
                do {
                    System.out.println("Choose one task to execute : ");
                    for (String taskId : taskInfoMapping.keySet()) {
                        System.out.println(taskId);
                    }

                    TaskConfig taskConfig = new TaskConfig();
                    JCommander.newBuilder().addObject(taskConfig).build().parse("-t");

                    TaskInfo toRunTask = taskInfoMapping.get(taskConfig.getTaskId());

                    Map<String, Boolean> mapping = new HashMap<>();
                    if (null != toRunTask) {
                        toRunTask.getStepId().forEach(stepId -> mapping.put(stepId, null));
                    }

                    for (PushStep step : pushInfo.getStep()) {
                        if (mapping.size() == 0 || mapping.containsKey(step.getId())) {
                            if (ActionType.UPLOAD.name().equalsIgnoreCase(step.getAction())) {
                                UploadProcessor.process(step, sessionMap);
                            } else if (ActionType.DOWNLOAD.name().equalsIgnoreCase(step.getAction())) {
                                DownloadProcessor.process(step, sessionMap);
                            } else if (ActionType.RX.name().equalsIgnoreCase(step.getAction())) {
                                RxProcessor.process(step, sessionMap);
                            } else if (ActionType.LX.name().equalsIgnoreCase(step.getAction())) {
                                LxProcessor.process(step, sessionMap);
                            } else {
                                System.err.printf("Invalid action : %s", JSON.toJSONString(step));

                                break;
                            }
                        }
                    }

                    yesOrNot = new YesOrNot();
                    System.out.println("Do you want to run another task : ");
                    JCommander.newBuilder().addObject(yesOrNot).build().parse("-confirm");
                } while ("Y".equalsIgnoreCase(yesOrNot.getYesOrNot()));
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (JSchException e) {
            e.printStackTrace();
        } catch (SftpException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            sessionMap.values().forEach(session -> session.disconnect());
        }
    }

    private static void printStepInfo(PushStep step) {
        if (ActionType.UPLOAD.name().equalsIgnoreCase(step.getAction())) {
            System.out.printf("\nUpload [ %s ] to [ %s ] @ %s\n", step.getSrc(), step.getTarget(), step.getHostId());
        } else if (ActionType.DOWNLOAD.name().equalsIgnoreCase(step.getAction())) {
            System.out.printf("\nDownload to [ %s ] from [ %s ] @ %s\n", step.getTarget(), step.getSrc(), step.getHostId());
        } else if (ActionType.RX.name().equalsIgnoreCase(step.getAction())) {
            System.out.printf("\nRX [ %s ] @ %s\n", step.getExec(), step.getHostId());
        } else if (ActionType.LX.name().equalsIgnoreCase(step.getAction())) {
            System.out.printf("\nLX [ %s ] @ %s\n", step.getExec(), step.getHostId());
        } else {
            throw new RuntimeException("Invalid action : %s".concat(JSON.toJSONString(step)));
        }
    }
}
